package rgbos.forum.GUI;

import java.security.MessageDigest;
import java.util.StringTokenizer;

import org.apache.commons.lang.StringEscapeUtils;
import org.omg.CORBA.UserException;

import rgbos.forum.domain.Auditor;
import rgbos.forum.exceptions.BrokenTopicException;
import rgbos.forum.exceptions.CantDeleteUserException;
import rgbos.forum.exceptions.EmptySearchResult;
import rgbos.forum.exceptions.HashException;
import rgbos.forum.exceptions.LoginDetailsIncorrect;
import rgbos.forum.exceptions.RGBOSServerException;
import rgbos.forum.exceptions.UserExeception;
import rgbos.forum.exceptions.UserExistsException;
import rgbos.forum.exceptions.UserNotModeratorException;

public class facade {

	private GuiClient client;
	private String username;
	private String permission;

	public facade() {
		super();

	}

	public void run(String host,int pass){
		this.client = new GuiClient(host,pass);
		this.client.run();
	}

	public String[][] getTopics() throws RGBOSServerException{
		String[][] topics ;

		String answer=this.client.invokeCmd("GET TOPICS CURRENT");
//		if(answer == null){
//			topics=new String[0][6];
//			return topics;
//		}
		if(answer==null || answer.isEmpty() || answer.startsWith("FAIL"))
			throw new RGBOSServerException();
		StringTokenizer topicsTxt=new StringTokenizer(answer,"|||");
		int topicsNum=topicsTxt.countTokens();
		topics=new String[topicsNum][6];
		int topicCounter=0;
		while(topicsTxt.hasMoreTokens()){
		String currTopicDetail=topicsTxt.nextToken();
			StringTokenizer topicDetails=new StringTokenizer(currTopicDetail,"~~~");
			int i=0;
			String[] currTopic=new String[6]; // id,title,author,creationDate,viewCount,postCount
			//System.out.println("\n\n\n");
			while(topicDetails.hasMoreTokens() && i<6){
				currTopic[i]=this.unescape(topicDetails.nextToken());
				i+=1;
			}
			topics[topicCounter]=currTopic;
			topicCounter+=1;
		}

		return topics;
	}

	public postDataStructure[] getPosts(int topicID) throws BrokenTopicException, RGBOSServerException{

		postDataStructure[] posts = null;
		String answer=this.client.invokeCmd("ENTER "+topicID);// (postID,title,author,date,PostBody)
		if (answer==null)
			throw new RGBOSServerException();
		if (answer.isEmpty())
			return new postDataStructure[0];
		StringTokenizer postsTxt=new StringTokenizer(answer,"|||");
		int postsNum=postsTxt.countTokens();
		posts=new postDataStructure[postsNum];
		int postCounter=0;
		while(postsTxt.hasMoreTokens()){
			String currPost=postsTxt.nextToken();
			StringTokenizer postDetails=new StringTokenizer(currPost,"~~~");
			if (postDetails.countTokens()!=5){
				while (postDetails.hasMoreTokens())
					System.out.println(postDetails.nextToken());
				throw new BrokenTopicException();
			}
			posts[postCounter]=new postDataStructure(this.unescape(postDetails.nextToken()),this.unescape(postDetails.nextToken()),this.unescape(postDetails.nextToken()),this.unescape(postDetails.nextToken()),this.unescape(postDetails.nextToken()));
			postCounter+=1;
		}
		return posts;
	}

	public String getPermission(){
		return this.permission;
	}

	//login return vals:
	//0 error
	//1 is success
	//2 is failure with pass
	//3 failure with username
	public int checkLoginDetails(String username,String password) throws RGBOSServerException,HashException, LoginDetailsIncorrect{
		String hashedPass=hashString(password);
		String answer=this.client.invokeCmd("LOGIN "+username+" "+hashedPass);
		if(answer==null || answer.isEmpty())
			throw new RGBOSServerException();
		if(answer.startsWith("FAIL"))
			throw new LoginDetailsIncorrect();
		String[] tokens=answer.split(" ");
		if (tokens[0].equals("SUCC") && tokens[1].equals("LOGIN")){
			this.username=tokens[2];
			this.permission=tokens[3];
			return 1;
		}
		if(tokens[2].equals("PASS"))
			return 2;
		if(tokens[2].equals("USER"))
			return 3;
		return 0;
	}

	public boolean register(String username,String password,String email) throws rgbos.forum.exceptions.UserExistsException, UserExeception{
		try {
			password=this.hashString(password);
		} catch (Exception e) {
			Auditor.Log("couldnt has pass of "+username, this.getClass());
		}
		String answer=this.client.invokeCmd("REGISTER "+username+" "+password+" "+email);
		String[] tokens=answer.split(" ");
		if (tokens[0].equals("FAIL"))
			if (tokens[2].equals("EXIST"))
				throw new UserExistsException();
			else
				throw new rgbos.forum.exceptions.UserExeception();
		return true;
	}

	public  boolean isValidEmailAddress(String aEmailAddress){
	    if (aEmailAddress == null) return false;
	    boolean result = true;
	    String[] tokens = aEmailAddress.split("@");
	     if (aEmailAddress.startsWith(".") || aEmailAddress.startsWith("@") || tokens.length!=2 || tokens[1].startsWith(".") || !tokens[1].contains(".")) {
	        result = false;
	      }
	    return result;
	  }

	public String getUsername() {
		return this.username;
	}

	public boolean updatePost(String postID,String title,String body) throws RGBOSServerException{
		String answer=this.client.invokeCmd("EDIT ~~~"+Integer.parseInt(postID)+"~~~"+title+"~~~"+body);
		if(answer==null || answer.isEmpty())
			throw new RGBOSServerException();
		if(answer.startsWith("FAIL"))
			return false;
		return true;
	}

	String[][] getUserList() throws RGBOSServerException{
		String answer  = this.client.invokeCmd("GET USERS");		
		return getUsersFromAnswer(answer);
	}
	
	String[][] getUsersFromAnswer(String answer) throws RGBOSServerException{
		if(answer==null || answer.isEmpty() || answer.startsWith("FAIL"))
			throw new RGBOSServerException();
		StringTokenizer st=new StringTokenizer(answer,"|||");
		int count=0;
		while(st.hasMoreTokens()){
			String curr2=st.nextToken();
			if (curr2!="")
				count+=1;			
		}
		st=new StringTokenizer(answer,"|||");
		//System.out.println(st.countTokens());
		String[][] result=new String[count][2];
		for (int i = 0; i < count; i++) {
			String curr=st.nextToken();
			StringTokenizer st22=new StringTokenizer(curr,"~~~");
			if (st22.countTokens()!=2)
				throw new RGBOSServerException();
			result[i][0]=st22.nextToken();
			result[i][1]=st22.nextToken();
		}
		return result;
	}
	
	boolean setModerator(String userID) throws RGBOSServerException{
		String answer=this.client.invokeCmd("SET MODERATOR "+userID);
		if(answer==null || answer.isEmpty())
			throw new RGBOSServerException();
		if(answer.startsWith("FAIL"))
			return false;
		return true;
	}

	public boolean addNewPost(int topicID,String postTitle,String postBody) throws RGBOSServerException{
		String answer=this.client.invokeCmd("ADD POST "+topicID+" |||"+postTitle+"|||"+postBody);
		if(answer==null || answer.isEmpty())
			throw new RGBOSServerException();
		if(answer.startsWith("FAIL"))
			return false;
		return true;
	}

	public boolean deletePost(String myPostId) throws RGBOSServerException {
		String answer = this.client.invokeCmd("DELETE POST "+myPostId );
		//System.out.println("deleted Post :"+myPostId);
		if(answer==null || answer.isEmpty())
			throw new RGBOSServerException();
		if(answer.startsWith("FAIL"))
			return false;
		return true;

	}


	public static String hashString(String str) throws HashException{
		byte[] passbytes = str.getBytes();
		String hashString = null;
		try{
		     MessageDigest algorithm = MessageDigest.getInstance("MD5");
		     algorithm.reset();
		     algorithm.update(passbytes);
		     byte messageDigest[] = algorithm.digest();

		     StringBuffer hexString = new StringBuffer();
		     for (int i=0;i<messageDigest.length;i++) {
			String hex = Integer.toHexString(0xFF & messageDigest[i]);
			if(hex.length()==1)
			hexString.append('0');

			hexString.append(hex);
			hashString = hexString.toString();
		     }
		}
		catch (Exception e) {
			//Auditor.Log("problem with hash ", "severe",this.getClass());
			throw new HashException();
		}
		return hashString;
	}

	public static void exitOnClose(){
		System.exit(0);
	}

	public void addNewTopic(String text) {
		this.client.invokeCmd("ADD TOPIC |||"+text);

	}

	public boolean updateUser(String username, String pass, String mail) throws HashException {
		String hashedPass = null;
		hashedPass=hashString(pass);
		String answer=this.client.invokeCmd("EDIT USER "+username+" "+hashedPass+" "+mail);
		//System.out.println(answer);
		return true;
	}
	
	public void logout() throws RGBOSServerException{
		String answer=this.client.invokeCmd("LOGOUT");
		if(answer==null || answer.isEmpty() || answer.startsWith("FAIL"))
			throw new RGBOSServerException();
	}

	public String getEmail() throws RGBOSServerException {
		String answer=this.client.invokeCmd("GET MAIL");
		if(answer==null || answer.isEmpty() || answer.startsWith("FAIL"))
			throw new RGBOSServerException();
		return answer;
	}

	public postDataStructure[] buildPostsFromSearch(String answer) throws RGBOSServerException {
		postDataStructure[] posts = null;
		// (postID,title,author,date,PostBody)
		if (answer==null || answer.isEmpty())
			throw new RGBOSServerException();
		StringTokenizer postsTxt=new StringTokenizer(answer,"|||");
		int postsNum=postsTxt.countTokens();
		if (postsNum==0)
			return null;
		posts=new postDataStructure[postsNum];
		int postCounter=0;
		while(postsTxt.hasMoreTokens()){
			String currPost=postsTxt.nextToken();
			StringTokenizer postDetails=new StringTokenizer(currPost,"~~~");
			posts[postCounter]=new postDataStructure(this.unescape(postDetails.nextToken()),this.unescape(postDetails.nextToken()),this.unescape(postDetails.nextToken()),this.unescape(postDetails.nextToken()),this.unescape(postDetails.nextToken()),this.unescape(postDetails.nextToken()));
			postCounter+=1;
		}
		return posts;
	}
	public postDataStructure[] searchByContent(String text) throws RGBOSServerException, EmptySearchResult {
		String answer=this.client.invokeCmd("SEARCH CONTENT |||"+text);	
		if(answer==null || answer.isEmpty())
			throw new RGBOSServerException();
		if(answer.startsWith("FAIL"))
			throw new EmptySearchResult();
		postDataStructure[] posts = buildPostsFromSearch(answer);
		return posts;
	}

	public postDataStructure[] searchByAuthor(String text) throws RGBOSServerException, EmptySearchResult {
		String answer=this.client.invokeCmd("SEARCH AUTHOR |||"+text);	
		if(answer==null || answer.isEmpty())
			throw new RGBOSServerException();
		if(answer.startsWith("FAIL"))
			throw new EmptySearchResult();
		postDataStructure[] posts = buildPostsFromSearch(answer);
		return posts;
		
	}

	public postDataStructure[] searchByDate(String text) throws RGBOSServerException, EmptySearchResult {
		String answer=this.client.invokeCmd("SEARCH DATE |||"+text);	
		if(answer==null || answer.isEmpty())
			throw new RGBOSServerException();
		if(answer.startsWith("FAIL"))
			throw new EmptySearchResult();
		postDataStructure[] posts = buildPostsFromSearch(answer);
		return posts;
		
	}

	public postDataStructure[] searchByDates(String text, String text2) throws RGBOSServerException, EmptySearchResult {
		String answer=this.client.invokeCmd("SEARCH DATES |||"+text+"|||"+text2);	
		if(answer==null || answer.isEmpty())
			throw new RGBOSServerException();
		if(answer.startsWith("FAIL"))
			throw new EmptySearchResult();
		postDataStructure[] posts = buildPostsFromSearch(answer);
		return posts;
		
	}

	public void deleteTopic(int id) throws RGBOSServerException {
		String answer=this.client.invokeCmd("DELETE TOPIC "+id+" ");
		if(answer==null || answer.isEmpty() || answer.startsWith("FAIL"))
			throw new RGBOSServerException();
	}

	public postDataStructure[] getTopicByPost(String postId) throws RGBOSServerException {
		postDataStructure[] posts = null;
		String answer=this.client.invokeCmd("GET TOPIC "+postId);// (postID,title,author,date,PostBody)
		if (answer==null ||answer.isEmpty())
			throw new RGBOSServerException();
		StringTokenizer postsTxt=new StringTokenizer(answer,"|||");
		int postsNum=postsTxt.countTokens();
		posts=new postDataStructure[postsNum];
		int postCounter=0;
		while(postsTxt.hasMoreTokens()){
			String currPost=postsTxt.nextToken();
			StringTokenizer postDetails=new StringTokenizer(currPost,"~~~");
			posts[postCounter]=new postDataStructure(this.unescape(postDetails.nextToken()),this.unescape(postDetails.nextToken()),this.unescape(postDetails.nextToken()),this.unescape(postDetails.nextToken()),this.unescape(postDetails.nextToken()));
			postCounter+=1;
		}
		return posts;
	}

	public String[][] getOnlineUsers() throws RGBOSServerException {
		String answer  = this.client.invokeCmd("GET ONLINE");
		return getUsersFromAnswer(answer);
	}

	public void RemoveModerator(String string) throws UserNotModeratorException,RGBOSServerException{
		String answer  = this.client.invokeCmd("PREM "+string);
		if(answer==null || answer.isEmpty())
			throw new RGBOSServerException();
		StringTokenizer st=new StringTokenizer(answer," ");
		if (st.countTokens()!=2)
			throw new RGBOSServerException();
		if (!st.nextToken().equals("SUCC"))
			throw new RGBOSServerException();;
		if(!st.nextToken().equals(MainFrame.MODERATOR_PERMISSION)){
			throw new UserNotModeratorException();
		}
			
		String answer2  = this.client.invokeCmd("REMOVE MODERATOR "+string);
		if(answer2==null || answer2.isEmpty() || answer2.startsWith("FAIL")){
			throw new RGBOSServerException();
		}
	}
	
	public void DeleteUser(String user) throws CantDeleteUserException{
		String answer  = this.client.invokeCmd("REMOVE USER "+user);
		if(answer==null || answer.isEmpty() || answer.startsWith("FAIL"))
			throw new CantDeleteUserException();
	}

	public boolean updateMail(String mail) throws RGBOSServerException {
		String answer  = this.client.invokeCmd("EDIT MAIL "+mail);
		if(answer==null || answer.isEmpty() || answer.startsWith("FAIL"))
			throw new RGBOSServerException();
		return true;
	}
	
	public String unescape(String text) {
		if (text == null)
			return "";
		String news=StringEscapeUtils.unescapeHtml(text).replaceAll("<br>", "\n");
		return news;
	}
	
}
